/*
 * Copyright 2013 JROSE
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jrose.service.webapp.exposer;

import lombok.NoArgsConstructor;
import org.jrose.api.annotation.remote.RequiredOperator;
import org.jrose.core.util.OperatorContext;
import org.jrose.entity.data.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter;
import org.springframework.remoting.support.RemoteInvocation;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;

@NoArgsConstructor
public class ExtendedHttpInvokerServiceExporter extends HttpInvokerServiceExporter {
    private static final Logger log = LoggerFactory.getLogger(ExtendedHttpInvokerServiceExporter.class);

    @Override
    protected RemoteInvocation readRemoteInvocation(HttpServletRequest request, InputStream is) throws IOException, ClassNotFoundException {
        RemoteInvocation remoteInvocation = super.readRemoteInvocation(request, is);
        String methodName = remoteInvocation.getMethodName();
        Class[] parameterTypes = remoteInvocation.getParameterTypes();
        try {
            //noinspection unchecked
            Method method = getServiceInterface().getMethod(methodName, parameterTypes);
            if (!method.isAnnotationPresent(RequiredOperator.class)) {
                return remoteInvocation;
            }

            User operator = (User) remoteInvocation.getAttribute(User.class.getName());
            if (operator == null) {
                throw new RuntimeException("No operator specified when invoke '" + method + "' on '" + getProxy().getClass().getName() + "'");
            }

            OperatorContext.getCurrentOperator().set(operator);
            return new ExtendedRemoteInvocation(remoteInvocation);
        } catch (NoSuchMethodException ex) {
            log.warn("No such method '{}' on '{}'", methodName, getProxy().getClass().getName());
            return remoteInvocation;
        }
    }
}
